package seedpod.kb2db;

/**
 * Copyright 2009 University of Washington This code is released under the GPL version 3 - with a copy of the license
 * included
 * 
 * @author Maya Hao Li
 */
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

import seedpod.model.RdbCls;
import seedpod.model.SeedpodModel;
import seedpod.model.rdb.MetaRdbCls;
import seedpod.model.rdb.Relation;
import seedpod.model.rdb.View;

public class ClsMap {

	public final static int MAP_CLS_TO_TABLE = 0;
	public final static int MAP_CLS_TO_TABLE_AND_VIEW = 2;
	public final static int MAP_CLS_TO_UNKNOWN = -1;
	public final static int MAP_CLS_TO_VIEW = 1;

	private HashMap<String, SlotMap> _domainSlotMaps = new HashMap<String, SlotMap>();
	final private ModelMap _map;
	private int _mapType = MAP_CLS_TO_UNKNOWN;
	private MetaRdbCls _metaRdbCls;
	// final private RdbCls _cls;
	private Relation _table = null;
	private View _view = null;
	private String _pk = null;

	public ClsMap(ModelMap map, MetaRdbCls metaCls) {
		_map = map;
		_metaRdbCls = metaCls;
		_table = new Relation( _metaRdbCls.getTableName() );
		_view = new View( _metaRdbCls.getViewName() );
	}

	// cls is not mapped to anything
	public ClsMap(ModelMap map, RdbCls rdbCls) {
		_map = map;
		_mapType = MAP_CLS_TO_UNKNOWN;
		_table = null;
		_view = null;
		_metaRdbCls = MetaRdbCls.create( rdbCls, null, null );
	}

	public ClsMap(ModelMap map, RdbCls rdbCls, Relation relation) {
		_map = map;
		_table = relation;
		_metaRdbCls = MetaRdbCls.create( rdbCls, relation, null );
		_mapType = MAP_CLS_TO_TABLE;
	}

	public ClsMap(ModelMap map, RdbCls rdbCls, View view) {
		_map = map;
		_view = view;
		_mapType = MAP_CLS_TO_VIEW;
		_metaRdbCls = MetaRdbCls.create( rdbCls, null, view );
	}

	public void addSlotMap( SlotMap slotMap ) {
		if ( slotMap == null ) return;
		_domainSlotMaps.put( slotMap.getName(), slotMap );
	}

	@Override
	public boolean equals( Object o ) {
		ClsMap ocm = (ClsMap)o;
		boolean sameRelation = false;
		boolean sameView = false;
		if ( _table != null )
			sameRelation = _metaRdbCls.getName().equals( ocm.getRdbClsName() ) && _table.getName().equals(
					ocm.getRelation().getName() );
		if ( _view != null )
			sameView = _metaRdbCls.getName().equals( ocm._metaRdbCls.getName() ) && _view.getName().equals(
					ocm.getRelation().getName() );
		return sameRelation || sameView;
	}

	public String getBrowserPattern() {
		return _metaRdbCls.getBrowserPattern();
	}

	// TODO
	public String[] getBrowserPatternArray() {
		String browserKey = getBrowserPattern();
		return browserKey.split( " " );
	}

	public Integer getCID() {
		return _metaRdbCls.getCid();
	}

	public String getClsType() {
		return _metaRdbCls.getClsType();
	}

	public String getDocumentation() {
		return _metaRdbCls.getDocumentation();
	}

	public Integer getFrameId() {
		return _metaRdbCls.getFrameId();
	}

	public ModelMap getMap() {
		return _map;
	}

	public int getMapType() {
		return _mapType;
	}

	public String getName() {
		return _metaRdbCls.getName();
	}

	public String getParentClsName() {
		return _metaRdbCls.getParentName();
	}

	public String getPrimaryKey() {
		if ( _pk == null ) _pk = _metaRdbCls.getPrimaryKey();
		return _pk;
	}

	public String getRdbClsName() {
		return _metaRdbCls.getName();
	}

	public Relation getRelation() {
		return _table != null ? _table : (Relation)_view;
	}

	public String getRelationName() {
		return _metaRdbCls.getTableName();
	}

	public SlotMap getSlotMap( String name ) {
		return _domainSlotMaps.get( name );
	}

	public ArrayList<SlotMap> getSlotMaps() {
		return new ArrayList<SlotMap>( _domainSlotMaps.values() );
	}

	public ArrayList<SlotMap> getSortedSlotMaps() {
		ArrayList<SlotMap> metaSlots = new ArrayList<SlotMap>( _domainSlotMaps.values() );
		Collections.sort( metaSlots );
		return metaSlots;
	}

	public String getTableName() {
		return _metaRdbCls.getTableName();
	}

	public String getUserDefinedName() {
		String uName = _metaRdbCls.getUserDefinedName();
		if ( uName == null || uName.length() == 0 ) uName = getName();
		return uName;
	}

	public View getView() {
		return _view;
	}

	public String getViewName() {
		return _metaRdbCls.getViewName();
	}

	public boolean hasAttribute( String slot ) {
		return _domainSlotMaps.keySet().contains( slot );
	}

	@Override
	public int hashCode() {
		int hash = 1;
		hash = hash * 31 + _metaRdbCls.getName().hashCode();
		if ( _table != null ) hash = hash * 31 + _table.getName().hashCode();
		if ( _view != null ) hash = hash * 31 + _view.getName().hashCode();
		return hash;
	}

	public boolean hasPrimaryKey() {
		return getPrimaryKey() != null || getPrimaryKey().length() != 0;
	}

	public Boolean isConcrete() {
		return _metaRdbCls.isConcrete();
	}

	public Boolean isInline() {
		return _metaRdbCls.isInline();
	}

	public boolean isRdbCls() {
		return _metaRdbCls.getClsType().equalsIgnoreCase( SeedpodModel.RdbCls.RDB_CLASS );
	}

	public boolean isReifiedRelation() {
		return _metaRdbCls.getParentName().equalsIgnoreCase( SeedpodModel.RdbCls.REIFIED_SLOT_CLS );
	}

	public boolean isSystemCls() {
		return _metaRdbCls.getParentName().equalsIgnoreCase( SeedpodModel.RdbCls.SYSTEM_CLASS );
	}

	public void serializeSQL( PrintWriter out ) {
		_metaRdbCls.serializeInstance( out );
	}

	public void setBrowserPattern( String pattern ) {
		_metaRdbCls.setBrowserPattern( pattern );
	}

	public void setDocumentation( String documentation ) {
		_metaRdbCls.setDocumentation( documentation );
	}

	public void setUserDefinedName( String userDefinedName ) {
		_metaRdbCls.setUserDefinedName( userDefinedName );
	}

	public void setView( View view ) {
		_view = view;
		if ( _table != null && _view != null ) _mapType = MAP_CLS_TO_TABLE_AND_VIEW;
		_metaRdbCls.setViewName( view.getName() );
	}

}
